﻿using Hangfire;
using Hangfire.Dashboard;
using Hangfire.Dashboard.BasicAuthorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using JESAI.Core.Modularity;
using JESAI.Schedule.HangFire.Abstrctions.BackgroundJobs;
using JESAI.Schedule.HangFire.BackgroundJobs.Hangfire;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Hangfire.MySql;

namespace JESAI.Schedule.HangFire;

[Description("Hangfire模块")]
public class HangfireModule : JESAIModule
{
    //private HangfireBackgroundJobServer _backgroundJobServer;

    /// <summary>
    /// 模块级别。级别越小越先启动
    /// </summary>
    public override ModuleLevel Level => ModuleLevel.Framework;

    /// <summary>
    /// 模块启动顺序。模块启动的顺序先按级别启动，同一级别内部再按此顺序启动，
    /// 级别默认为0，表示无依赖，需要在同级别有依赖顺序的时候，再重写为>0的顺序值
    /// </summary>
    public override int Order => 1;

    /// <summary>
    /// 添加服务。将模块服务添加到依赖注入服务容器中
    /// </summary>
    /// <param name="services">服务集合</param>
    public override IServiceCollection AddServices(IServiceCollection services)
    {
        ////var preActions = services.GetPreConfigureActions<IGlobalConfiguration>();
        var config = services.GetConfiguration();

        services.AddHangfireServer((Options) => { Options.Queues = new[] { "systemqueue", "bizqueue", "netqueue", "dataqueue" }; });

        services.AddHangfire(configuration =>
        {
            if (config["Hangfire:DatabaseType"] == "InMemory")
            {
                configuration.UseInMemoryStorage();
            }
            else
            {
                configuration.UseStorage(
                   new MySqlStorage(config["DbConnOptions:Url"],
                   new MySqlStorageOptions
                   {
                       TablesPrefix = "JESAI_" + "HangFire",
                   }));

            }
            //configuration.UseInMemoryStorage();

            //preActions.Configure(configuration);
        });

        services.AddTransient(serviceProvider =>
           serviceProvider.GetRequiredService<DashboardOptionsProvider>().Get());

        services.AddSingleton(serviceProvider =>
        {
            var options = serviceProvider.GetRequiredService<IOptions<HangfireOptions>>().Value;
            return new HangfireBackgroundJobServer(options.BackgroundJobServerFactory.Invoke(serviceProvider));
        });

        RegisterJobs(services);
        return services;
    }

    /// <summary>
    /// 应用模块服务
    /// </summary>
    /// <param name="provider">服务提供程序</param>
    public override void UseModule(IServiceProvider provider)
    {
        var options = provider.GetRequiredService<IOptions<BackgroundJobOptions>>().Value;
        if (!options.IsJobExecutionEnabled)
        {
            var hangfireOptions = provider.GetRequiredService<IOptions<HangfireOptions>>().Value;
            hangfireOptions.BackgroundJobServerFactory = CreateOnlyEnqueueJobServer;
        }


    }

    public override void UseModule(IApplicationBuilder app)
    {
        //app.UseHangfireServer();
        var config = app.ApplicationServices.GetService<IConfiguration>();

        app.UseHangfireDashboard(options: new DashboardOptions
        {
            Authorization = new[]
            {
                    new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions
                    {
                        RequireSsl = false,
                        SslRedirect = false,
                        LoginCaseSensitive = true,
                        Users = new []
                        {
                            new BasicAuthAuthorizationUser
                            {
                                Login = config["Hangfire:Login"],
                                PasswordClear =  config["Hangfire:Password"]
                            }
                        }
                    })
                },
            DashboardTitle = "任务调度中心",

        });

        //app.UseHangfireServer(new BackgroundJobServerOptions()
        //{
        //    Queues = new[] { "systemqueue", "bizqueue", "netqueue", "dataqueue"}
        //});
    }

    private BackgroundJobServer CreateOnlyEnqueueJobServer(IServiceProvider serviceProvider)
    {
        serviceProvider.GetRequiredService<JobStorage>();
        return null;
    }

    private static void RegisterJobs(IServiceCollection services)
    {
        var jobTypes = new List<Type>();

        //services.OnRegistred(context =>
        //{
        //    if (ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IBackgroundJob<>)) ||
        //        ReflectionHelper.IsAssignableToGenericType(context.ImplementationType, typeof(IAsyncBackgroundJob<>)))
        //    {
        //        jobTypes.Add(context.ImplementationType);
        //    }
        //});

        services.Configure<BackgroundJobOptions>(options =>
        {
            foreach (var jobType in jobTypes)
            {
                options.AddJob(jobType);
            }
        });

        //public override void OnApplicationInitialization(ApplicationInitializationContext context)
        //{
        //    _backgroundJobServer = context.ServiceProvider.GetRequiredService<HangfireBackgroundJobServer>();
        //}

        //public override void OnApplicationShutdown(ApplicationShutdownContext context)
        //{
        //    if (_backgroundJobServer == null)
        //    {
        //        return;
        //    }

        //    _backgroundJobServer.HangfireJobServer?.SendStop();
        //    _backgroundJobServer.HangfireJobServer?.Dispose();
        //}
    }
}
